#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 6868


void setnonblocking(int sock)
{
	int opts;
	opts = fcntl(sock,F_GETFL);
	if(opts < 0)
	{
		perror("fcntl");
		exit(-1);
	}

	opts = opts | O_NONBLOCK;
	if(fcntl(sock,F_SETFL,opts) < 0)
	{
		perror("fcntl");
		exit(-1);
	}

}

int create_sock(void)
{
	int sock = 0;
	int ret = 0;
	
	struct sockaddr_in clientaddr,seraddr;
	memset(&clientaddr,0,sizeof(clientaddr));
	memset(&seraddr,0,sizeof(seraddr));
	int size = sizeof(clientaddr);


	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(PORT);
	seraddr.sin_addr.s_addr = INADDR_ANY;

	sock = socket(AF_INET,SOCK_STREAM,0);
	if(sock < 0)
	{
		perror("sock");
		exit(-1);
	}

	ret = bind(sock,(struct sockaddr *)&seraddr,sizeof(struct sockaddr));
	if(ret < 0)
	{
		perror("bind");
		exit(-1);
	}

	ret = listen(sock,5);
	if(ret < 0)
	{
		perror("listen");
		exit(-1);
	}

	return sock;
}


#define MAX_EVENTS 10
int main()
{
	struct epoll_event ev,events[MAX_EVENTS];
	int ret = 0;
	int listen_sock = 0,conn_sock = 0,nfds = 0,epollfd = 0;
	int i = 0;
	char buf[1024] = {0};


	listen_sock = create_sock();

	epollfd = epoll_create1(0);
	if(epollfd == -1)
	{
		perror("epoll_create1");
		exit(EXIT_FAILURE);
	}

	ev.events = EPOLLIN;
	ev.data.fd = listen_sock;

	ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);
	if(ret == -1)
	{
		perror("epoll_ctl:listen_sock");
		exit(EXIT_FAILURE);
	}


	for(;;)
	{
		nfds = epoll_wait(epollfd,events,MAX_EVENTS,-1);
		if(nfds == -1)
		{
			perror("epoll_wait");
			exit(EXIT_FAILURE);
		}

		for(i = 0;i < nfds;i++)
		{
			if(events[i].data.fd == listen_sock)
			{
				conn_sock = accept(listen_sock,NULL,NULL);
				if(conn_sock == -1)
				{
					perror("accept");
					exit(EXIT_FAILURE);
				}

				setnonblocking(conn_sock);
				ev.events = EPOLLIN | EPOLLET;
				ev.data.fd = conn_sock;

				ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,conn_sock,&ev);
				if(ret == -1)
				{
					perror("epoll_ctl:conn_sock");
					exit(EXIT_FAILURE);
				}
			}else
			{
				ret = recv(events[i].data.fd,buf,5,0);
				if(ret < 0)
				{
					perror("recv");
					exit(-1);
				}
				if(ret == 0)
				{
					ev.data.fd = events[i].data.fd;
					ev.events = EPOLLIN;
					ret = epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,&ev);
					if(ret == -1)
					{
						perror("epoll_ctl:delete");
						exit(EXIT_FAILURE);
					}
					close(ev.data.fd);
				}

				printf("buf is %s\n",buf);

			}
		}
	}


	return 0;
}








